package com.yxy.springcloud.framework.unionauth.service;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.yxy.springcloud.framework.common.base.BusinessException;
import com.yxy.springcloud.framework.common.base.PageDataList;
import com.yxy.springcloud.framework.common.redis.RedisUtils;
import com.yxy.springcloud.framework.common.utils.MD5Util;
import com.yxy.springcloud.framework.unionauth.DTO.*;
import com.yxy.springcloud.framework.unionauth.dao.*;
import com.yxy.springcloud.framework.unionauth.model.*;
import com.yxy.springcloud.framework.unionauth.utils.TokenCheckUtil;
import com.yxy.springcloud.framework.unionauth.vo.UserExtend;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;

/**
 * app user(AdminUser)相关service
 */
@Slf4j
@Service
public class UserService {
  @Autowired
  private TokenCheckUtil tokenCheckUtil;

  @Resource
  private RedisUtils redisUtils;

  @Resource
  private TenantMapper tenantMapper;

  @Resource
  private AdminUserMapper adminUserMapper;

  @Resource
  private UserRoleMapper userRoleMapper;

  @Resource
  private UserTenantMapper userTenantMapper;

  @Resource
  private RoleMapper roleMapper;

  public PageDataList<UserExtend> getList(UserListDto query) {
    List<UserExtend> resultList = new ArrayList<>();

    PageHelper.startPage(query.getPageNumber(), query.getPageSize());
    PageHelper.orderBy("t1.create_date desc");//排序
    List<AdminUser> dbResult = adminUserMapper.selectList(query);
    Page<AdminUser> dbResultPage = (Page<AdminUser>) dbResult;

    for (AdminUser dbItem : dbResultPage.getResult()) {
      Long userId = dbItem.getId();
      UserExtend userExtend = new UserExtend();
      BeanUtils.copyProperties(dbItem, userExtend);
      List<Tenant> tenantList = adminUserMapper.getTenantListWithUser(userId);
      List<App> appList = adminUserMapper.getAppListWithUser(userId);
      List<Role> roleList = adminUserMapper.getRoleListWithUser(userId);
      userExtend.setTenantList(tenantList);
      userExtend.setRoleList(roleList);
      userExtend.setAppList(appList);
      resultList.add(userExtend);
    }

    PageDataList<UserExtend> pageDataList = new PageDataList<>(dbResultPage.getTotal(),
            dbResultPage.getPages(),
            dbResultPage.getPageNum(), dbResultPage.getPageSize());
    pageDataList.setList(resultList);
    return pageDataList;

  }

  @Transactional(rollbackFor = Exception.class)
  public Map<String, Object> createOrUpdate(AppUserCreateDto inputDto) throws BusinessException {
    // 参数合法校验
    String[] selectedTenantIdList = inputDto.getSelectedTenantIdList();
    if (selectedTenantIdList == null || selectedTenantIdList.length == 0) {
      throw new BusinessException(501, "需要至少选择一个租户");
    }

    String[] selectedRoleIdList = inputDto.getSelectedRoleIdList();
    if (selectedRoleIdList == null || selectedRoleIdList.length == 0) {
      throw new BusinessException(501, "需要至少选择一个角色");
    }
    // end
    Map<String, Object> resultMap = new HashMap<>();
    String curUserStr = tokenCheckUtil.getUserInfoByToken();
    AuthAdminUser loginUser = JSON.parseObject(curUserStr, AuthAdminUser.class);
    if (loginUser == null) {
      // app后台通过feign调用该接口时,不能按正常的逻辑取得loginUser
      loginUser = new AuthAdminUser();
      loginUser.setId(-1L);
      loginUser.setName("app后台");
    }
    Long id = inputDto.getId();
    if (id == null) { // insert
      AdminUser insertObj = new AdminUser();
      BeanUtils.copyProperties(inputDto, insertObj);
      InsertBaseEntity baseEntity = new InsertBaseEntity(loginUser.getId(), loginUser.getName());
      BeanUtils.copyProperties(baseEntity, insertObj);
      //设置初始密码与用户名相同
      if (inputDto.isSelfPasswordFlag()) {
        insertObj.setPassword(MD5Util.stringMD5(inputDto.getPassword()).toLowerCase());
      } else {
        insertObj.setPassword(MD5Util.stringMD5(inputDto.getUsername()).toLowerCase());
      }
      adminUserMapper.insertUseGeneratedKeys(insertObj);
      resultMap.put("id", insertObj.getId());
      // 创建租户和app user的关系
      this.createUserTenantRelation(inputDto, insertObj.getId(), loginUser);
      // 创建 app user 与 role 的对应关系
      this.createUserRoleRelation(inputDto, insertObj.getId(), loginUser);
    } else { // update
      AdminUser updateObj = new AdminUser();
      BeanUtils.copyProperties(inputDto, updateObj);
      updateObj.setId(id);
      updateObj.setUpdateUserId(loginUser.getId());
      updateObj.setUpdateUserName(loginUser.getName());
      updateObj.setUpdateDate(new Date());
      adminUserMapper.updateByPrimaryKeySelective(updateObj);
      resultMap.put("id", id);
      // 修改租户和app user的关系
      // 为了方便,先全删,然后再添加
      this.deleteUserTenantRelation(inputDto, id);
      this.deleteUserRoleRelation(inputDto, id);
      // 创建 user_tenant表
      this.createUserTenantRelation(inputDto, id, loginUser);
      // 创建 user_role表
      this.createUserRoleRelation(inputDto, id, loginUser);
    }
    return resultMap;
  }

  @Transactional(rollbackFor = Exception.class)
  public Map<String, Object> createOrUpdate2(AppUserCreateDto2 inputDto) throws BusinessException {
    AppUserCreateDto inputDtoFinal = new AppUserCreateDto();
    BeanUtils.copyProperties(inputDto, inputDtoFinal);
    // 将app code+selectedRoleNameList转换成selectedRoleIdList
    List<Role> roles = roleMapper.getRoleWithRoleNameAndApp(inputDto.getAppCode(), inputDto.getSelectedRoleNameList());
    List<String> selectedRoleIdList = new ArrayList<>();
    for (Role role : roles) {
      selectedRoleIdList.add(role.getId().toString());
    }
    String[] selectedRoleIdListFinal = new String[selectedRoleIdList.size()];
    selectedRoleIdList.toArray(selectedRoleIdListFinal);
    inputDtoFinal.setSelectedRoleIdList(selectedRoleIdListFinal);
    return this.createOrUpdate(inputDtoFinal);
  }

  // 创建 user和tenant的对应关系
  private void createUserTenantRelation(AppUserCreateDto inputDto, Long userId, AuthAdminUser loginUser) {
    // 创建租户和app user的关系
    List<UserTenant> insertObjList = new ArrayList<>();
    String[] tenantIdList = inputDto.getSelectedTenantIdList();
    for (int index = 0; index < tenantIdList.length; index++) {
      String tenantIdStr = tenantIdList[index];
      Long tenantId = Long.parseLong(tenantIdStr);
      UserTenant userTenantInsertObj = new UserTenant();
      userTenantInsertObj.setTenantId(tenantId);
      userTenantInsertObj.setUserId(userId);
      InsertBaseEntity baseEntity = new InsertBaseEntity(loginUser.getId(), loginUser.getName());
      BeanUtils.copyProperties(baseEntity, userTenantInsertObj);
      insertObjList.add(userTenantInsertObj);
    }
    if (insertObjList.size() > 0) {
      userTenantMapper.insertList(insertObjList);
    }
  }

  // 删除过时的 app user和tenant的对应关系
  private void deleteUserTenantRelation(AppUserCreateDto inputDto, Long userId) {
    UserTenant delObj = new UserTenant();
    delObj.setUserId(userId);
    userTenantMapper.delete(delObj);
  }

  // 创建 user和role的对应关系
  private void createUserRoleRelation(AppUserCreateDto inputDto, Long userId, AuthAdminUser loginUser) {
    // 创建role和app user的关系
    List<UserRole> insertObjList = new ArrayList<>();
    String[] roleIdList = inputDto.getSelectedRoleIdList();
    for (int index = 0; index < roleIdList.length; index++) {
      String roleIdStr = roleIdList[index];
      Long roleId = Long.parseLong(roleIdStr);
      UserRole insertObj = new UserRole();
      insertObj.setRoleId(roleId);
      insertObj.setUserId(userId);
      InsertBaseEntity baseEntity = new InsertBaseEntity(loginUser.getId(), loginUser.getName());
      BeanUtils.copyProperties(baseEntity, insertObj);
      insertObjList.add(insertObj);
    }
    if (insertObjList.size() > 0) {
      userRoleMapper.insertList(insertObjList);
    }
  }

  // 删除过时的 app user和role的对应关系
  private void deleteUserRoleRelation(AppUserCreateDto inputDto, Long userId) {
    UserRole delObj = new UserRole();
    delObj.setUserId(userId);
    userRoleMapper.delete(delObj);
  }

  @Transactional(rollbackFor = Exception.class)
  public void delete(long id) throws BusinessException {
    // app user逻辑删除
    String curUserStr = tokenCheckUtil.getUserInfoByToken();
    AuthAdminUser loginUser = JSON.parseObject(curUserStr, AuthAdminUser.class);
    if (loginUser == null) {
      // app后台通过feign调用该接口时,不能按正常的逻辑取得loginUser
      loginUser = new AuthAdminUser();
      loginUser.setId(-1L);
      loginUser.setName("app后台");
    }
    AdminUser updateObj = new AdminUser();
    updateObj.setId(id);
    updateObj.setStatus(1L);
    updateObj.setUpdateUserId(loginUser.getId());
    updateObj.setUpdateUserName(loginUser.getName());
    updateObj.setUpdateDate(new Date());
    adminUserMapper.updateByPrimaryKeySelective(updateObj);
    // 删除用户与租户的对应关系
    UserTenant deleteObj = new UserTenant();
    deleteObj.setUserId(id);
    userTenantMapper.delete(deleteObj);
    // 删除用户与 角色的对应关系
    UserRole delObj2 = new UserRole();
    delObj2.setUserId(id);
    userRoleMapper.delete(delObj2);
  }

  public void resetPasswordForOuter(ChangePasswordForOuterDto inputDto) throws BusinessException {
    List<AdminUser> appUserList = adminUserMapper.findUserByUsernameAndApp(inputDto);
    int userCount = appUserList.size();
    if (userCount == 0) {
      log.error("根据app code和username查找不到一个具体的app 用户");
      throw new BusinessException(510, "根据app code和username查找不到一个具体的app 用户");
    }
    if (userCount > 1) {
      log.error("根据app code和username查找到不止一个具体的app 用户");
      throw new BusinessException(511, "根据app code和username查找到不止一个具体的app 用户");
    }
    long userId = appUserList.get(0).getId();
    this.resetPasswordForInner(userId, inputDto.getNewPassword());
  }

  public void resetPasswordForInner(long userId, String newPassword) throws BusinessException {
    String curUserStr = tokenCheckUtil.getUserInfoByToken();
    AuthAdminUser loginUser = JSON.parseObject(curUserStr, AuthAdminUser.class);

    AdminUser updateObj = new AdminUser();
    updateObj.setId(userId);
    updateObj.setPassword(MD5Util.stringMD5(newPassword).toLowerCase());
    updateObj.setUpdateUserId(loginUser.getId());
    updateObj.setUpdateUserName(loginUser.getName());
    updateObj.setUpdateDate(new Date());
    adminUserMapper.updateByPrimaryKeySelective(updateObj);
  }

}
